home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK1.toast / Development Kits (Disc 1) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Circular Layout ƒ / Circular Layout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-06-18  |  17.5 KB  |  523 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Circular Layout.c
  5. |**|
  6. |**|    This file contains the calls that this sample needs to make
  7. |**|    the QuickDraw GX shell work correctly.
  8. |**|
  9. |**|    QuickDraw GX Libraries Used:
  10. |**|    "ColorLibrary.c", "FontLibrary.c", "GraphicsDebugLibrary.c",
  11. |**|    "LayoutLibrary.c", "ShapeLibrary.c", and "TransformLibrary.c".
  12. |**|
  13. |**|    6/96 bob    Updated #includes to support changed GX Library names.
  14. |**|                Updated the copyright date.
  15. |**|
  16. |**|    ©1990 - 1996  Apple Computer, Inc.
  17. |**|    All rights reserved.
  18. |**|
  19. |**| =====================================================================
  20. \**/
  21.  
  22.  
  23. #include "QDGX shell.h"
  24. #include <GXLayout.h>
  25. #include "LayoutLibrary.h"
  26.  
  27.  
  28. /**\
  29. |**| ---------------------------------------------------------------------
  30. |**| PROTOTYPES
  31. |**| ---------------------------------------------------------------------
  32. \**/
  33.  
  34. // funtions required by shell
  35.  
  36. void    DoSetup            (void);
  37. void    DoDraw            (WindowPtr wind, Boolean updating);
  38. OSErr    DoCreateNew        (void);
  39. void    DoDispose        (WindowPtr wind);
  40. void    DoIdle            (WindowPtr wind);
  41. void    DoTeardown        (void);
  42. void    DoClick            (WindowPtr wind, Point p);
  43.  
  44. // private functions
  45.  
  46. OSErr    DoWindowInit        (WindowPtr wind);
  47. void    CreateSampleImage    (WindowPtr wind);
  48.  
  49.  
  50. /**\
  51. |**| ---------------------------------------------------------------------
  52. |**| ENUMS
  53. |**| ---------------------------------------------------------------------
  54. \**/
  55. enum { rWindResource = 128 };
  56.  
  57.  
  58. /**\
  59. |**| ---------------------------------------------------------------------
  60. |**| GLOBALS
  61. |**| ---------------------------------------------------------------------
  62. \**/
  63. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  64. // functionality will only work with the "debugging" version of QuickDraw GX.
  65. // If the debugging version is not installed, nothing bad will happen, but these
  66. // functions will not work. 
  67.  
  68. Boolean        gDebugging = true;
  69.  
  70. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  71.  
  72. Boolean        gGiveMeValidation = true;
  73.  
  74.  
  75. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  76. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  77. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  78. // since we need abunch if we have several windows open.
  79.  
  80. long        gGraphicsHeapSize = 600;
  81.  
  82. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  83. // override.  This is so that our override can be native PowerPC code if necessary.
  84.  
  85. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  86.  
  87.  
  88.  
  89. /**\
  90. |**| ---------------------------------------------------------------------
  91. |**| DoSetup()
  92. |**| Here's where we initialize any global variables our application needs.
  93. |**| We have only one at this time -- the universal proc pointer for
  94. |**| our printing override.
  95. |**| ---------------------------------------------------------------------
  96. \**/
  97. void DoSetup (void)
  98. {    // Initialize our printing event override UPP
  99.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  100. }
  101.  
  102.  
  103. /**\
  104. |**| ---------------------------------------------------------------------
  105. |**| DoDraw()
  106. |**| Draw the contents of the window.  The first parameter is the window
  107. |**| to draw, and the second parameter is true if we're updating an existing
  108. |**| image.  If that's the case, we should redraw the ampersand shape and not
  109. |**| change the oval shape any.  If we do all our rotations and color 
  110. |**| adjustments on update events, when the system sets the clipping to only
  111. |**| the update region, the window gets terribly befuddled.  So, to counter
  112. |**| this, no changes are made to the shapes if we're updating, and we don't
  113. |**| erase the old shapes, but we _do_ draw the ampersand shape.
  114. |**| It sounds weird, but it works well.  Try it.
  115. |**| ---------------------------------------------------------------------
  116. \**/
  117. void DoDraw(WindowPtr wind, Boolean updating)
  118. {
  119.     gxShape            eraseOval;
  120.     gxShape            drawOval;
  121.     gxColor            drawOvalColor;
  122.     gxDashRecord    ourDash;
  123.     gxColor            gColorWhite = xRGB (0xFFFF, 0xFFFF, 0xFFFF);    
  124.     
  125. // First, initialize our document variables.
  126.  
  127.     drawOval = GetDocOvalShape(wind);
  128.     if (!updating)
  129.     {
  130.         (void *) GXGetShapeColor(drawOval, &drawOvalColor);
  131.         (void *) GXGetShapeDash(drawOval, &ourDash);
  132.  
  133. // Get the erasing oval from the document's structure. 
  134. // Drawing this "erase oval" on a white background wipes out the last drawing of
  135. // the drawOval shape.  We then cache it so we can draw it as fast as possible
  136. // later in this routine.
  137.  
  138.         eraseOval = GetDocEraseShape(wind);            // get the erasing shape
  139.         GXCopyToShape(eraseOval, drawOval);            // copy drawOval's geometry to eraseOval
  140.         GXSetShapeColor(eraseOval, &gColorWhite);     // set eraseOval's color to white
  141.         GXCacheShape(eraseOval);                    // make this draw faster below
  142.  
  143. // We now can erase the last-drawn oval when we please by drawing eraseOval.  Now,
  144. // we turn to drawing the next rotation of the drawOval.  First, we increment the
  145. // hue by 1/32 (in fixed notation) and increment the dash's phase by the same amount
  146. // (but this time in fract notation).
  147.  
  148.         drawOvalColor.element.hsv.hue += fixed1/32;
  149.         drawOvalColor.element.hsv.saturation += fixed1/24;
  150.         drawOvalColor.element.hsv.value += fixed1/20;
  151.         ourDash.phase += fract1/32;
  152.     
  153. // To make the changes to ourDash and drawOvalColor take effect, we have to stuff
  154. // them back in the shape.  Then we cache the drawOval shape so it will draw faster.
  155.  
  156.         GXSetShapeColor (drawOval, &drawOvalColor);
  157.         GXSetShapeDash (drawOval, &ourDash);
  158.         GXCacheShape (drawOval);
  159.         
  160. // Guess what?  GXGetShapeDash makes a copy of the dashing shape, so now we need
  161. // to dispose of it!  (This wasn't obvious to me, and took me some time to figure
  162. // out, so I'm boring you with this interesting tidbit in revenge.)
  163.  
  164.         GXDisposeShape(ourDash.dash);
  165.         
  166.     }
  167.  
  168. // Now we're ready to erase the old oval and draw the new one!  If we're updating,
  169. // draw the ampersand as well.
  170.  
  171.     if (!updating)
  172.         GXDrawShape(eraseOval);
  173.     GXDrawShape (drawOval);
  174.     
  175. }
  176.  
  177.  
  178. /**\
  179. |**| ---------------------------------------------------------------------
  180. |**| DoCreateNew()
  181. |**| This routine is called when a window needs to be created.
  182. |**| ---------------------------------------------------------------------
  183. \**/
  184. OSErr DoCreateNew (void)
  185. {
  186.     OSErr        err = noErr;
  187.     WindowPtr    wind;
  188.     
  189. // Get and create our window from the resource fork
  190.  
  191.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  192.  
  193. // Attach a default gxViewPort to it, create and iInitialize our
  194. // private data for it, and add a sample image to its page shape.
  195.  
  196.     if ( wind == NULL )
  197.         return (MemError());
  198.  
  199.     GXIgnoreGraphicsNotice(transform_already_set);
  200.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  201.     GXPopGraphicsNotice();
  202.     
  203.     err = DoWindowInit(wind);
  204.     if ( err != noErr )
  205.         return err;
  206.     
  207.     CreateSampleImage(wind);
  208.     return err;
  209. }
  210.  
  211.  
  212. /**\
  213. |**| ---------------------------------------------------------------------
  214. |**| DoDispose()
  215. |**| This routine is called when a window needs to be disposed of.
  216. |**| ---------------------------------------------------------------------
  217. \**/
  218. void DoDispose (WindowPtr wind)
  219. {
  220.     TH_Doc    doc;
  221.     
  222. // You should always dispose of your GX graphics objects before tossing your window.
  223. // Why?  It's generally good form and this approach guarantees that everything is
  224. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  225. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  226. // with notices set, you will receive a notice that you had not disposed of everything.
  227. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  228.     
  229.     if ( wind != NULL )
  230.     {
  231.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  232.         GXDisposeShape(GetDocOvalShape(wind));     // Dispose of this doc's oval.
  233.         GXDisposeShape(GetDocEraseShape(wind));    // Dispose of this doc's erasing shape
  234.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  235.         DisposHandle((Handle) doc);            // Dispose of our private data.
  236.         DisposeWindow(wind);                // Dispose of the window.
  237.     }
  238. }
  239.  
  240.  
  241. /**\
  242. |**| ---------------------------------------------------------------------
  243. |**| DoIdle()
  244. |**| This routine is called to do things while idling through the event loop.
  245. |**| ---------------------------------------------------------------------
  246. \**/
  247. void DoIdle (WindowPtr wind)
  248. {
  249.     if ( wind != NULL )
  250.         if ((((WindowPeek)wind)->windowKind == userKind) && (wind != nil))
  251.             DoDraw(wind, false);
  252. }
  253.  
  254. /**\
  255. |**| ---------------------------------------------------------------------
  256. |**| DoTeardown()
  257. |**| This routine is called just before we quit to remove anything 
  258. |**| persistent that might have been setup by DoSetup().
  259. |**| ---------------------------------------------------------------------
  260. \**/
  261. void DoTeardown (void)
  262. {
  263.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  264. }
  265.  
  266.  
  267. /**\
  268. |**| ---------------------------------------------------------------------
  269. |**| DoClick()
  270. |**| ---------------------------------------------------------------------
  271. \**/
  272. void DoClick(WindowPtr window, Point p)
  273. {
  274. }
  275.  
  276.  
  277.  
  278.  
  279.  
  280. /**\
  281. |**| ---------------------------------------------------------------------
  282. |**| DoWindowInit()
  283. |**| In this function we create and initialize the the private document
  284. |**| structure for a new window.  This structure contains the print job and
  285. |**| the shape which is drawn in the window.  We store this data in a handle
  286. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  287. |**| this, rather than using globals, we can create many windows containing
  288. |**| unique print jobs and shapes.
  289. |**| ---------------------------------------------------------------------
  290. \**/
  291. OSErr DoWindowInit (WindowPtr wind)
  292. {
  293.     OSErr    err = noErr;
  294.     gxJob    docJob;
  295.     TH_Doc    windDoc;
  296.  
  297.  
  298. // Create a print job for this document.  This will be the same as the system default until
  299. // the user goes through the dialogs for Page Setup or Print…
  300.  
  301.     err = GXNewJob(&docJob);
  302.     
  303.     
  304. // If there are no errors, create a handle the size of our document structure and store
  305. // the print job in it.  Store the handle in the window's refCon field so that we can
  306. // get at it.  (Note that the utility routine "GetDocJob" can be used to do this easily.
  307.  
  308.     if ( err == noErr )
  309.     {
  310.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  311.  
  312.         if ( windDoc == NULL )
  313.             err = MemError();
  314.         else
  315.         {
  316.             (*windDoc)->docJob = docJob;
  317.             SetWRefCon(wind, (long) windDoc);
  318.         }
  319.  
  320. // Now install our application override for PrintingEvent so that we can
  321. // support the new movable-modal printing dialog boxes.
  322.  
  323.         GXInstallApplicationOverride(docJob, gxPrintingEventMsg, gOurPrintingOverrideUPP);
  324.  
  325.     }
  326.  
  327.     return err;
  328. }
  329.  
  330.  
  331. /**\
  332. |**| ---------------------------------------------------------------------
  333. |**| CreateSampleImage()
  334. |**| This function creates primitive shapes and adds them to the window's page shape.
  335. |**| ---------------------------------------------------------------------
  336. \**/
  337. void CreateSampleImage (WindowPtr wind)
  338. {
  339.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  340.                                             // in QuickDraw coordinates
  341.     gxShape         layout;                        // the layout shape we dash the oval with
  342.     gxShape         oval;                        // the oval that the layout lives in
  343.     gxShape            eraseOval;                    // another oval shape to erase with
  344.     gxDashRecord     ourDash;                    // the record for our complex dash
  345.     gxColor         ovalColor;                    // the color for the oval
  346.     gxRectangle     bounds;                        // the bounds of various shapes (reused)
  347.     gxRectangle        ourRectangle;                // the rectangle for the oval's use
  348.     gxRunControls     runControls;                // default run controls for layouts
  349.     gxLayoutOptions layoutOptions;                // default layout options for layouts
  350.     char             *textRuns[3];                // array of text runs for our dash layout
  351.     gxStyle         textStyles[3];                // array of styles for our dash layout
  352.     short             textLengths[3];                // array of lengths for our dash layout
  353.     short            totalLength;                // total length of the text
  354.     short            level0 = 0;                    // variable for use with GXNewLayout
  355.     char *            text1  = "Aetna ";            // text run #1
  356.  
  357. //  Text run #2 is "Arabic Macintosh" in Arabic: 
  358. //  meem, alif, kaf,  noon, tah,  wau,  shin, <sp>, alif, lam,  ein,  reh,  beh,  yeh 
  359.  
  360.     static char     text2[] =  {0xE5, 0xC7, 0xE3, 0xE6, 0xCA, 0xE8, 0xD4,
  361.                                 0x20, 0xC7, 0xE4, 0xD9, 0xD1, 0xC8, 0xEA, 0};
  362.                                 
  363.     char *            text3  = " Office AWAY.";    // text run #3
  364.     gxPoint         center;                        // center of all the graphics we do
  365.     
  366.  
  367. // Find the center of the window in fixed coordinates
  368.  
  369.     center.x = ff((ourWindowRect.right - ourWindowRect.left) / 2);
  370.     center.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  371.         
  372. // Make a 270 x 270 gxRectangle centered in the window 
  373.  
  374.     ourRectangle.top = center.y - ff(135);
  375.     ourRectangle.left = center.x - ff(135);
  376.     ourRectangle.bottom = center.y + ff(135);
  377.     ourRectangle.right = center.x + ff(135);
  378.     
  379. // Use ourRectangle to make an oval, and get it ready to be dashed.
  380.  
  381.     oval = NewOval(&ourRectangle);
  382.     GXSetShapeFill(oval, gxClosedFrameFill);
  383.     GXSetShapePen(oval, IntToFixed(14));
  384.     (void *) SetCommonColor(&ovalColor, red);
  385.     (void *) GXConvertColor(&ovalColor, gxHSVSpace, nil, nil);    // convert to HSV
  386.     
  387. // Copy the same oval to our eraseOval shape so we can use it later.
  388.  
  389.     eraseOval = GXNewShape(gxPathType);
  390.     GXCopyToShape(eraseOval, oval);
  391.  
  392. // Initialize the array of text runs for our layout shape
  393.  
  394.     textRuns[0] = text1;
  395.     textRuns[1] = text2;
  396.     textRuns[2] = text3;
  397.     
  398. // Initialize the text lengths.  MyStrLength is a function in this file.
  399.  
  400.     textLengths[0] = MyStrLength(text1);
  401.     textLengths[1] = MyStrLength(text2);
  402.     textLengths[2] = MyStrLength(text3);
  403.     
  404.     totalLength = textLengths[0] + textLengths[1] + textLengths[2];
  405.  
  406. // Use library routines to initialize default gxLayoutOptions and gxRunControls structures
  407.  
  408.     InitializeLayoutOptions (&layoutOptions);
  409.     InitializeRunControls (&runControls);
  410.     
  411. // Use the library routines to initialize three style runs.  The first one is 28-point
  412. // Helvetica.  NewLayoutStyle is found in layout library.c.
  413.  
  414.     textStyles[0] = NewLayoutStyle(
  415.         (char *) "\pHoefler Text",            // the gxFontName for the style
  416.         ff(28),                            // the point size in fixed point
  417.         0,                                // gxTextAttributes (none)
  418.         &runControls,                    // our default run controls
  419.         nil,                            // run features (none for us)
  420.         0,                                // count of run features
  421.         nil);                            // style run overrides (none for us)
  422.  
  423. // The second one is 28-point Baghdad.
  424.  
  425.     textStyles[1] = NewLayoutStyle(
  426.         (char *) "\pBaghdad Plain",        // the gxFontName for the style
  427.         ff(28),                            // the point size in fixed format
  428.         0,                                // gxTextAttributes (none)
  429.         &runControls,                    // our default run controls
  430.         nil,                            // run featuers (none for this style)
  431.         0,                                 // count of run features
  432.         nil);                            // style run overrides (none for us)
  433.     
  434. // The third and final one is 28-point Times Roman
  435.  
  436.     textStyles[2] = NewLayoutStyle(
  437.         (char *) "\pHoefler Text Italic",// the gxFontName for this style
  438.         ff(28),                            // the point size (fixed format)
  439.         0,                                // no gxTextAttributes
  440.         &runControls,                    // our default run controls
  441.         nil,                            // no run features
  442.         0,                                // count of no run features = 0
  443.         nil);                            // style run overrides (still none)
  444.     
  445. // We're ready to build our layout now!
  446.  
  447.     layout = GXNewLayout(
  448.         3,                                    // count of text runs
  449.         textLengths,                        // array of lengths of each run
  450.         (void *)textRuns,                    // array of pointers to the text
  451.         3,                                    // count of style runs
  452.         textLengths,                        // array of the byte lengths of each run
  453.         textStyles,                            // array of the styles
  454.         1,                                    // number of levels in the layout
  455.         &totalLength,                        // array of lengths of levels (only one)
  456.         &level0,                            // array of the levels (only one)
  457.         &layoutOptions,                        // options (default)
  458.         nil);                                // position of the layout shape (none)
  459.         
  460.     GXSetShapeColor(layout, &ovalColor);
  461.         
  462. // Now we get the bounds of the layout shape to determine how to proceed with the dashing.
  463. // Why are we using GXGetShapeBounds instead of GXGetShapeTypographicBounds?  The latter
  464. // does not include the size of any hanging punctuation in the width; the former does.
  465. // Since we're only interested in the width this time, that's the call we want.
  466.  
  467.     (void) GXGetShapeBounds (layout, 0, &bounds);
  468.     
  469. // Changing the shape to a path type will make dashing it faster.  We could also call
  470. // GXPrimitiveShape twice to do this (the first time makes a glyph shape).
  471.  
  472.     GXSetShapeType(layout, gxPathType);
  473.     
  474. // We're ready to use the layout/path shape as the dash shape for our oval.
  475. // Initialize our dash record and use it!
  476.  
  477.     ourDash.attributes = 
  478.         gxAutoAdvanceDash | gxBreakDash;        // use whole multiples of dash shapes
  479.     ourDash.dash = layout;                        // the shape to dash with
  480.     ourDash.phase = 0;                            // the initial phase
  481.     ourDash.advance = bounds.right + ff(10);    // the advance (shape size + 10 pixels)
  482.     ourDash.scale = IntToFixed(14);                // the scale perpendicular to contour
  483.  
  484.     GXSetShapeDash (oval, &ourDash);
  485.  
  486. // Now scale the oval shape to fill the window.
  487.     
  488.     GXScaleShape(
  489.         oval,                                // the shape to get the transform from
  490.         (Fixed)0x00016000,                    // scale it horizontally by 1 3/8
  491.         (Fixed)0x00016000,                    // and vertically by 1 3/8
  492.         center.x,                            // about the center of the rectangle
  493.         center.y);                            // as previously determined
  494.     
  495.  
  496. // Save the layout and ampersand shapes for this window in the doc structure
  497. // attached to this document.
  498.     
  499.     {
  500.     
  501.         TH_Doc    windDoc;                    // the document structure
  502.         
  503.         windDoc = (TH_Doc) GetWRefCon(wind);
  504.         (*windDoc)->docOval = oval;
  505.         (*windDoc)->eraseOval = eraseOval;
  506.         
  507.     }
  508.         
  509.         
  510. // Dispose of all things we allocated in here that we don't need to keep.
  511.  
  512.     GXDisposeShape(layout);
  513.     GXDisposeStyle (textStyles[0]);
  514.     GXDisposeStyle (textStyles[1]);
  515.     GXDisposeStyle (textStyles[2]);
  516.  
  517.  
  518. // Invalidate the window's portRect so that everything gets updated.
  519.     
  520.     SetPort(wind);
  521.     InvalRect(&ourWindowRect);
  522. }
  523.